//! Completion tests for attributes.
use expect_test::expect;

use crate::tests::{check, check_edit};

#[test]
fn derive_helpers() {
    check(
        r#"
//- /mac.rs crate:mac
#![crate_type = "proc-macro"]

#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))]
pub fn my_derive() {}

//- /lib.rs crate:lib deps:mac
#[rustc_builtin_macro]
pub macro derive($item:item) {}

#[derive(mac::MyDerive)]
pub struct Foo(#[m$0] i32);
"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at derive                                  macro derive
            at derive(…)
            at diagnostic::do_not_recommend
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at ignore = "…"
            at inline
            at link
            at link_name = "…"
            at link_section = "…"
            at macro_export
            at macro_use
            at must_use
            at my_cool_helper_attribute derive helper of `MyDerive`
            at no_mangle
            at non_exhaustive
            at panic_handler
            at path = "…"
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at repr(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at used
            at warn(…)
            md mac
            kw crate::
            kw self::
        "#]],
    )
}

#[test]
fn proc_macros() {
    check(
        r#"
//- proc_macros: identity
#[$0]
struct Foo;
"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at derive(…)
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at non_exhaustive
            at repr(…)
            at warn(…)
            md proc_macros
            kw crate::
            kw self::
        "#]],
    )
}

#[test]
fn proc_macros_on_comment() {
    check(
        r#"
//- proc_macros: identity
/// $0
#[proc_macros::identity]
struct Foo;
"#,
        expect![[r#""#]],
    )
}

#[test]
fn proc_macros_qualified() {
    check(
        r#"
//- proc_macros: identity
#[proc_macros::$0]
struct Foo;
"#,
        expect![[r#"
            at identity proc_macro identity
        "#]],
    )
}

#[test]
fn with_existing_attr() {
    check(
        r#"#[no_mangle] #[$0] mcall!();"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at expect(…)
            at forbid(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    )
}

#[test]
fn attr_on_source_file() {
    check(
        r#"#![$0]"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at crate_name = ""
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at feature(…)
            at forbid(…)
            at must_use
            at no_implicit_prelude
            at no_main
            at no_mangle
            at no_std
            at recursion_limit = "…"
            at type_length_limit = …
            at warn(…)
            at windows_subsystem = "…"
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_module() {
    check(
        r#"#[$0] mod foo;"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at macro_use
            at must_use
            at no_mangle
            at path = "…"
            at warn(…)
            kw crate::
            kw self::
            kw super::
        "#]],
    );
    check(
        r#"mod foo {#![$0]}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_implicit_prelude
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
            kw super::
        "#]],
    );
}

#[test]
fn attr_on_macro_rules() {
    check(
        r#"#[$0] macro_rules! foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at macro_export
            at macro_use
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_macro_def() {
    check(
        r#"#[$0] macro foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_extern_crate() {
    check(
        r#"#[$0] extern crate foo;"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at macro_use
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_use() {
    check(
        r#"#[$0] use foo;"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_type_alias() {
    check(
        r#"#[$0] type foo = ();"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_struct() {
    check(
        r#"
//- minicore:derive
#[$0]
struct Foo;
"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at derive             macro derive
            at derive(…)
            at derive_const macro derive_const
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at non_exhaustive
            at repr(…)
            at warn(…)
            md core
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_enum() {
    check(
        r#"#[$0] enum Foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at derive(…)
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at non_exhaustive
            at repr(…)
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_const() {
    check(
        r#"#[$0] const FOO: () = ();"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_static() {
    check(
        r#"#[$0] static FOO: () = ()"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at link_name = "…"
            at link_section = "…"
            at must_use
            at no_mangle
            at used
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_trait() {
    check(
        r#"#[$0] trait Foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_impl() {
    check(
        r#"#[$0] impl () {}"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at diagnostic::do_not_recommend
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
    check(
        r#"impl () {#![$0]}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_with_qualifier() {
    check(
        r#"#[diagnostic::$0] impl () {}"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at do_not_recommend
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at warn(…)
        "#]],
    );
    check(
        r#"#[diagnostic::$0] trait Foo {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at must_use
            at no_mangle
            at on_unimplemented
            at warn(…)
        "#]],
    );
}

#[test]
fn attr_diagnostic_on_unimplemented() {
    check(
        r#"#[diagnostic::on_unimplemented($0)] trait Foo {}"#,
        expect![[r#"
            ba label = "…"
            ba message = "…"
            ba note = "…"
        "#]],
    );
    check(
        r#"#[diagnostic::on_unimplemented(message = "foo", $0)] trait Foo {}"#,
        expect![[r#"
            ba label = "…"
            ba note = "…"
        "#]],
    );
    check(
        r#"#[diagnostic::on_unimplemented(note = "foo", $0)] trait Foo {}"#,
        expect![[r#"
            ba label = "…"
            ba message = "…"
            ba note = "…"
        "#]],
    );
}

#[test]
fn attr_on_extern_block() {
    check(
        r#"#[$0] extern {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at link
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
    check(
        r#"extern {#![$0]}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at forbid(…)
            at link
            at must_use
            at no_mangle
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_variant() {
    check(
        r#"enum Foo { #[$0] Bar }"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at deny(…)
            at expect(…)
            at forbid(…)
            at non_exhaustive
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_on_fn() {
    check(
        r#"#[$0] fn main() {}"#,
        expect![[r#"
            at allow(…)
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at ignore = "…"
            at inline
            at link_name = "…"
            at link_section = "…"
            at must_use
            at no_mangle
            at panic_handler
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn attr_in_source_file_end() {
    check(
        r#"#[$0]"#,
        expect![[r#"
            at allow(…)
            at automatically_derived
            at cfg(…)
            at cfg_attr(…)
            at cold
            at deny(…)
            at deprecated
            at derive(…)
            at diagnostic::do_not_recommend
            at diagnostic::on_unimplemented
            at doc = "…"
            at doc = include_str!("…")
            at doc(alias = "…")
            at doc(hidden)
            at expect(…)
            at export_name = "…"
            at forbid(…)
            at global_allocator
            at ignore = "…"
            at inline
            at link
            at link_name = "…"
            at link_section = "…"
            at macro_export
            at macro_use
            at must_use
            at no_mangle
            at non_exhaustive
            at panic_handler
            at path = "…"
            at proc_macro
            at proc_macro_attribute
            at proc_macro_derive(…)
            at repr(…)
            at should_panic
            at target_feature(enable = "…")
            at test
            at track_caller
            at used
            at warn(…)
            kw crate::
            kw self::
        "#]],
    );
}

#[test]
fn invalid_path() {
    check(
        r#"
//- proc_macros: identity
#[proc_macros:::$0]
struct Foo;
"#,
        expect![[r#""#]],
    );

    check(
        r#"
//- minicore: derive, copy
mod foo {
    pub use Copy as Bar;
}
#[derive(foo:::::$0)]
struct Foo;
"#,
        expect![""],
    );
}

#[test]
fn issue_17479() {
    check(
        r#"
//- proc_macros: issue_17479
fn main() {
    proc_macros::issue_17479!("te$0");
}
"#,
        expect![""],
    );
    check(
        r#"
//- proc_macros: issue_17479
fn main() {
    proc_macros::issue_17479!("$0");
}
"#,
        expect![""],
    )
}

mod cfg {
    use super::*;

    #[test]
    fn inside_cfg() {
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg($0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg(b$0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
    }

    #[test]
    fn inside_cfg_attr() {
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr($0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr(b$0)]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr($0, allow(deprecated))]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
        check(
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg_attr(b$0, allow(deprecated))]
"#,
            expect![[r#"
                ba all
                ba any
                ba dbg
                ba not
                ba opt_level
                ba test
                ba true
            "#]],
        );
    }

    #[test]
    fn cfg_target_endian() {
        check(
            r#"#[cfg(target_endian = $0"#,
            expect![[r#"
                ba big
                ba little
            "#]],
        );
        check(
            r#"#[cfg(target_endian = b$0"#,
            expect![[r#"
                ba big
                ba little
            "#]],
        );
    }

    #[test]
    fn inside_conditional() {
        check_edit(
            "all",
            r#"
//- /main.rs cfg:test,dbg=false,opt_level=2
#[cfg($0)]
"#,
            r#"
#[cfg(all($0))]
"#,
        );
    }
}

mod derive {
    use super::*;

    #[test]
    fn no_completion_for_incorrect_derive() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive{$0)] struct Test;
"#,
            expect![[]],
        )
    }

    #[test]
    fn empty_derive() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive($0)] struct Test;
"#,
            expect![[r#"
                de Clone              macro Clone
                de Clone, Copy
                de Debug              macro Debug
                de Default          macro Default
                de PartialEq      macro PartialEq
                de PartialEq, Eq
                de PartialEq, Eq, PartialOrd, Ord
                de PartialEq, PartialOrd
                md core
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_with_input_before() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
"#,
            expect![[r#"
                de Clone     macro Clone
                de Clone, Copy
                de Debug     macro Debug
                de Default macro Default
                de Eq
                de Eq, PartialOrd, Ord
                de PartialOrd
                md core
                kw crate::
                kw self::
            "#]],
        )
    }

    #[test]
    fn derive_with_input_after() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive($0 serde::Serialize, PartialEq)] struct Test;
"#,
            expect![[r#"
                de Clone     macro Clone
                de Clone, Copy
                de Debug     macro Debug
                de Default macro Default
                de Eq
                de Eq, PartialOrd, Ord
                de PartialOrd
                md core
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_with_existing_derives() {
        check(
            r#"
//- minicore: derive, copy, clone, ord, eq, default, fmt
#[derive(PartialEq, Eq, Or$0)] struct Test;
"#,
            expect![[r#"
                de Clone     macro Clone
                de Clone, Copy
                de Debug     macro Debug
                de Default macro Default
                de PartialOrd
                de PartialOrd, Ord
                md core
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_flyimport() {
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive
#[derive(der$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity (use proc_macros::DeriveIdentity) proc_macro DeriveIdentity
                md core
                md proc_macros
                kw crate::
                kw self::
            "#]],
        );
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive
use proc_macros::DeriveIdentity;
#[derive(der$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity proc_macro DeriveIdentity
                md core
                md proc_macros
                kw crate::
                kw self::
            "#]],
        );
    }

    #[test]
    fn derive_flyimport_edit() {
        check_edit(
            "DeriveIdentity",
            r#"
//- proc_macros: derive_identity
//- minicore: derive
#[derive(der$0)] struct Test;
"#,
            r#"
use proc_macros::DeriveIdentity;

#[derive(DeriveIdentity)] struct Test;
"#,
        );
    }

    #[test]
    fn qualified() {
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive, copy, clone
#[derive(proc_macros::$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity proc_macro DeriveIdentity
            "#]],
        );
        check(
            r#"
//- proc_macros: derive_identity
//- minicore: derive, copy, clone
#[derive(proc_macros::C$0)] struct Test;
"#,
            expect![[r#"
                de DeriveIdentity proc_macro DeriveIdentity
            "#]],
        );
    }
}

mod lint {
    use super::*;

    #[test]
    fn lint_empty() {
        check_edit(
            "deprecated",
            r#"#[allow($0)] struct Test;"#,
            r#"#[allow(deprecated)] struct Test;"#,
        )
    }

    #[test]
    fn lint_with_existing() {
        check_edit(
            "deprecated",
            r#"#[allow(keyword_idents, $0)] struct Test;"#,
            r#"#[allow(keyword_idents, deprecated)] struct Test;"#,
        )
    }

    #[test]
    fn lint_qualified() {
        check_edit(
            "deprecated",
            r#"#[allow(keyword_idents, $0)] struct Test;"#,
            r#"#[allow(keyword_idents, deprecated)] struct Test;"#,
        )
    }

    #[test]
    fn lint_feature() {
        check_edit(
            "box_patterns",
            r#"#[feature(box_$0)] struct Test;"#,
            r#"#[feature(box_patterns)] struct Test;"#,
        )
    }

    #[test]
    fn lint_clippy_unqualified() {
        check_edit(
            "clippy::as_conversions",
            r#"#[allow($0)] struct Test;"#,
            r#"#[allow(clippy::as_conversions)] struct Test;"#,
        );
    }

    #[test]
    fn lint_clippy_qualified() {
        check_edit(
            "as_conversions",
            r#"#[allow(clippy::$0)] struct Test;"#,
            r#"#[allow(clippy::as_conversions)] struct Test;"#,
        );
    }

    #[test]
    fn lint_rustdoc_unqualified() {
        check_edit(
            "rustdoc::bare_urls",
            r#"#[allow($0)] struct Test;"#,
            r#"#[allow(rustdoc::bare_urls)] struct Test;"#,
        );
    }

    #[test]
    fn lint_rustdoc_qualified() {
        check_edit(
            "bare_urls",
            r#"#[allow(rustdoc::$0)] struct Test;"#,
            r#"#[allow(rustdoc::bare_urls)] struct Test;"#,
        );
    }

    #[test]
    fn lint_unclosed() {
        check_edit(
            "deprecated",
            r#"#[allow(dep$0 struct Test;"#,
            r#"#[allow(deprecated struct Test;"#,
        );
        check_edit(
            "bare_urls",
            r#"#[allow(rustdoc::$0 struct Test;"#,
            r#"#[allow(rustdoc::bare_urls struct Test;"#,
        );
    }
}

mod repr {
    use super::*;

    #[test]
    fn no_completion_for_incorrect_repr() {
        check(r#"#[repr{$0)] struct Test;"#, expect![[]])
    }

    #[test]
    fn empty() {
        check(
            r#"#[repr($0)] struct Test;"#,
            expect![[r#"
                ba C
                ba align($0)
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba packed
                ba transparent
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn transparent() {
        check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]);
    }

    #[test]
    fn align() {
        check(
            r#"#[repr(align(1), $0)] struct Test;"#,
            expect![[r#"
                ba C
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba transparent
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn packed() {
        check(
            r#"#[repr(packed, $0)] struct Test;"#,
            expect![[r#"
                ba C
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba transparent
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn c() {
        check(
            r#"#[repr(C, $0)] struct Test;"#,
            expect![[r#"
                ba align($0)
                ba i16
                ba i28
                ba i32
                ba i64
                ba i8
                ba isize
                ba packed
                ba u128
                ba u16
                ba u32
                ba u64
                ba u8
                ba usize
            "#]],
        );
    }

    #[test]
    fn prim() {
        check(
            r#"#[repr(usize, $0)] struct Test;"#,
            expect![[r#"
                ba C
                ba align($0)
                ba packed
            "#]],
        );
    }
}

mod macro_use {
    use super::*;

    #[test]
    fn completes_macros() {
        check(
            r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
    () => {};
}

#[macro_export]
macro_rules! bar {
    () => {};
}

//- /main.rs crate:main deps:dep
#[macro_use($0)]
extern crate dep;
"#,
            expect![[r#"
                ma bar
                ma foo
            "#]],
        )
    }

    #[test]
    fn only_completes_exported_macros() {
        check(
            r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
    () => {};
}

macro_rules! bar {
    () => {};
}

//- /main.rs crate:main deps:dep
#[macro_use($0)]
extern crate dep;
"#,
            expect![[r#"
                ma foo
            "#]],
        )
    }

    #[test]
    fn does_not_completes_already_imported_macros() {
        check(
            r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
    () => {};
}

#[macro_export]
macro_rules! bar {
    () => {};
}

//- /main.rs crate:main deps:dep
#[macro_use(foo, $0)]
extern crate dep;
"#,
            expect![[r#"
                ma bar
            "#]],
        )
    }
}
